package org.yangjie.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.yangjie.config.security.TokenAuthenticationFilter;
import org.yangjie.config.security.TokenAuthenticationProvider;
/**
 * @EnableGlobalMethodSecurity(securedEnabled=true)
 *	开启@Secured 注解过滤权限
 * @EnableGlobalMethodSecurity(jsr250Enabled=true)
 *	开启@RolesAllowed 注解过滤权限 
 * @EnableGlobalMethodSecurity(prePostEnabled=true)
 *	使用表达式实现方法级别的安全性 4个注解可用
 *	@PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
 *	@PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
 *	@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
 *	@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true) // 开启方法级别安全验证
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{

//	@Autowired
//	private UserDetailsServiceImpl userDetailsServiceImpl;
	@Autowired
	private TokenAuthenticationFilter tokenAuthenticationFilter;
	@Autowired
	private TokenAuthenticationProvider tokenAuthenticationProvider;
	
	
	/**
	 * 安全策略配置
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 自定义登录授权配置
		http.csrf().disable(); // 关闭csrf
		http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 禁用http session
		http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); // 自定义token过滤器
//		http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); // 自定义认证失败异常处理
//		http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 自定义授权失败异常处理

		// 通过用户名密码登录相关配置
//		http.authorizeRequests().antMatchers("/admin").hasRole("ADMIN"); // 拥有权限可访问, 注意配置顺序, 需要在anyRequest()之前
//		http.authorizeRequests().antMatchers("/user").hasRole("USER"); // 拥有权限可访问, 注意配置顺序, 需要在anyRequest()之前
//		http.authorizeRequests().anyRequest().authenticated(); // 拦截所有请求
//		http.httpBasic(); // 使用basic认证 默认用户名user 密码见启动日志
//		http.formLogin(); // 使用表单登录, 需要配合configure(AuthenticationManagerBuilder auth)使用
	}
	
	/**
	 * 认证管理器配置
	 * 用户信息来源有三种: 
	 * 1 内存用户: auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN")
	 * 2 数据库用户: auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query)
	 * 3 自定义用户: 实现接口 org.springframework.security.core.userdetails.UserDetailsService
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.authenticationProvider(tokenAuthenticationProvider); // 自定义token认证处理器
//        auth.userDetailsService(userDetailsServiceImpl) // 自定义org.springframework.security.core.userdetails.UserDetailsService
//        	.passwordEncoder(new BCryptPasswordEncoder()); // 指定密码编码器, 保存用户时需要使用相同编码器
	}

}
